package com.lp.yupao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lp.yupao.common.ErrorCode;
import com.lp.yupao.exception.BusinessException;
import com.lp.yupao.mapper.UserTeamMapper;
import com.lp.yupao.model.domain.Team;
import com.lp.yupao.model.domain.User;
import com.lp.yupao.model.domain.UserTeam;
import com.lp.yupao.model.domain.request.TeamJoinRequest;
import com.lp.yupao.model.domain.request.TeamSearchRequest;
import com.lp.yupao.model.domain.request.TeamUpdateRequest;
import com.lp.yupao.model.vo.TeamVO;
import com.lp.yupao.model.vo.UserVO;
import com.lp.yupao.service.TeamService;
import com.lp.yupao.mapper.TeamMapper;
import com.lp.yupao.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.lp.yupao.model.enums.TeamStatusEnums.*;

/**
 * @author lp337
 * @description 针对表【team(队伍)】的数据库操作Service实现
 * @createDate 2024-05-18 21:01:51
 */
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService {
    @Resource
    private UserService userService;
    @Resource
    private TeamMapper teamMapper;
    @Resource
    private UserTeamMapper userTeamMapper;

    /**
     * 创建队伍
     *
     * @param teamRequest 队伍数据
     * @param request     请求
     * @return 队伍id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public long createTeam(Team teamRequest, HttpServletRequest request) {
        // 校验该队伍是否可以创建
        // 1.判断是否登录
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        final long loginUserId = loginUser.getId();
        // 2.队伍人数 > 1 且 <= 20
        Integer maxNum = teamRequest.getMaxNum();
        if (!(maxNum > 1 && maxNum <= 20)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍人数不符合规则");
        }
        // 3.队伍标题 <= 20
        String teamName = teamRequest.getName();
        int teamNameLength = teamName.length();
        if (!(teamNameLength <= 20)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍标题不符合规则");
        }
        // 4.描述 <= 512
        String description = teamRequest.getDescription();
        int desLength = description.length();
        if (!(desLength <= 512)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍描述不符合规则");
        }
        // 5.如果 status 是加密状态，一定要有密码，且密码 <= 32
        Integer status = teamRequest.getStatus();
        String password = teamRequest.getPassword();
        int pwdLength = password.length();
        if (status == ENCRYPTION.getKey() && !(pwdLength > 0 && pwdLength <= 32)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍必须设置密码");
        }
        // 6.超时时间 > 当前时间
        Date expireTime = teamRequest.getExpireTime();
        Date now = new Date();
        if (!(expireTime.after(now))) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍描述不符合规则");
        }
        // 7.校验用户最多创建 5 个队伍
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", loginUserId);
        Long teamCount = teamMapper.selectCount(queryWrapper);
        if (teamCount >= 5) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建队伍个数不能大于5");
        }
        // 插入队伍信息到队伍表
        Team team = new Team();
        BeanUtils.copyProperties(teamRequest, team);
        team.setUserId(loginUserId);
        //加密
        password = teamRequest.getPassword();
        String safetyPwd = DigestUtils.md5DigestAsHex(password.getBytes());
        team.setPassword(safetyPwd);
        int insertResult = teamMapper.insert(team);
        // 插入用户  => 队伍关系到关系表
        // 查队伍数据 获取队长创建本次队伍的时间
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", loginUserId);
        queryWrapper.orderByDesc("id");
        Page page = teamMapper.selectPage(new Page<>(), queryWrapper);
        Team loginUserTeam = (Team) page.getRecords().get(0);
        // 封装成员-队伍关系对象
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(loginUserId);
        userTeam.setTeamId(loginUserTeam.getId());
        // 队长的进队时间就是创建队伍的时间
        userTeam.setJoinTime(loginUserTeam.getCreateTime());
        userTeamMapper.insert(userTeam);
        return insertResult;
    }

    /**
     * 更新队伍信息
     *
     * @param teamRequest 队伍信息
     * @param request     请求
     * @return 更新后的队伍信息
     */
    @Override
    public long updateTeam(TeamUpdateRequest teamRequest, HttpServletRequest request) {
        // 判断是否登录
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        // 查询队伍是否存在
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", teamRequest.getId());
        Team result = teamMapper.selectOne(queryWrapper);
        if (result == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍不存在");
        }
        // 只有管理员和本人可以修改
        if (!(loginUser.getUserRole() == 1 || teamRequest.getUserId() == loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        // todo 判断新值是否与老值相同
        // 状态为加密必须有密码
        Integer status = teamRequest.getStatus();
        String password = teamRequest.getPassword();
        Team team = new Team();
        if (password != null) {
            if (status.equals(ENCRYPTION.getKey()) && password.length() == 0) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "请设置密码");
            }
            BeanUtils.copyProperties(teamRequest, team);
            if (password.length() > 0) {
                //加密
                password = teamRequest.getPassword();
                String safetyPwd = DigestUtils.md5DigestAsHex(password.getBytes());
                team.setPassword(safetyPwd);
            }
        }
        BeanUtils.copyProperties(teamRequest, team);
        int updateResult = teamMapper.updateById(team);
        if (updateResult == 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新数据库失败");
        }
        return updateResult;
    }

    /**
     * 根据条件查询队伍数据（支持分页）
     *
     * @param teamSearchRequest 查询条件
     * @param request           请求
     * @return 队伍数据列表
     */
    @Override
    public List<TeamVO> searchTeamList(TeamSearchRequest teamSearchRequest, HttpServletRequest request) {
        // 判断是否登录
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        // 根据条件封装查询语句
        Long id = teamSearchRequest.getId();
        // 根据id筛选
        if (id != null) {
            queryWrapper.eq("id", id);
        }
        // 根据过期时间筛选
        // expireTime > now() or expireTime is null
        queryWrapper.and(qw -> qw.gt("expireTime", new Date()).or().isNull("expireTime"));
        // 根据队名筛选
        String name = teamSearchRequest.getName();
        if (name != null) {
            queryWrapper.eq("name", name);
        }
        // 根据描述查询
        String description = teamSearchRequest.getDescription();
        if (description != null) {
            queryWrapper.eq("description", description);
        }
        // 根据关键词模糊查询队名和描述
        String searchText = teamSearchRequest.getSearchText();
        if (searchText != null) {
            queryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
        }
        // 根据最大人数筛选
        Integer maxNum = teamSearchRequest.getMaxNum();
        if (maxNum != null) {
            queryWrapper.eq("maxNum", maxNum);
        }
        // 不能查私有的
        Integer status = teamSearchRequest.getStatus();
        if (!PRIVATE.getKey().equals(status)) {
            queryWrapper.eq("status", status);
        }
        // 查数据库
        List<Team> teamList = new ArrayList<>();
        Long pageNum = teamSearchRequest.getPageNum();
        Long pageSize = teamSearchRequest.getPageSize();
        if (pageNum != null && pageSize != null) {
            // 执行分页查询
            Page<Team> teamPage = teamMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
            teamList = teamPage.getRecords();
        } else {
            // 全表查询
            teamList = teamMapper.selectList(queryWrapper);
        }
        if (teamList == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        // 脱敏队伍信息
        List<TeamVO> teamVOList = new ArrayList<>();
        for (Team team : teamList) {
            UserVO userVO = new UserVO();
            TeamVO teamVO = new TeamVO();
            // 获取队长的id
            Long userId = team.getUserId();
            if (userId == null) {
                continue;
            }
            // 查询队伍加入人数
            List<UserTeam> userListByTeamId = getUserListByTeamId(team.getId());
            teamVO.setHasJoinNum(userListByTeamId.size());
            // 通过id查询信息
            User user = userService.getById(userId);
            // 判断登录用户又没有加入队伍
            for (UserTeam userTeam : userListByTeamId) {
                if (userTeam.getUserId() == loginUser.getId()) {
                    teamVO.setHasJoin(true);
                }
            }
            // 插入数据
            BeanUtils.copyProperties(user, userVO);
            BeanUtils.copyProperties(team, teamVO);
            teamVO.setUserVO(userVO);
            teamVOList.add(teamVO);
        }
        return teamVOList;
    }

    /**
     * 加入队伍
     *
     * @param teamJoinRequest 请求参数（队伍id，密码）
     * @param request         请求
     * @return 是否加入成功
     */
    @Override
    public int insertTeam(TeamJoinRequest teamJoinRequest, HttpServletRequest request) {
        long teamId = teamJoinRequest.getTeamId();
        String password = teamJoinRequest.getPassword();
        // 判断是否登录
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        final long loginUserId = loginUser.getId();
        // 用户最多加入5个队伍
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("userId", loginUserId);
        // 用户加入的队伍
        List<UserTeam> userInsertTeamList = userTeamMapper.selectList(userTeamQueryWrapper);
        if (userInsertTeamList.size() >= 5) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "最多加入5支队伍");
        }
        // 只能加入未满，未过期的队伍
        QueryWrapper<Team> teamQueryWrapper = new QueryWrapper<>();
        teamQueryWrapper.eq("id", teamId);
        // 要加入的队伍信息
        Team team = teamMapper.selectOne(teamQueryWrapper);
        Date expireTime = team.getExpireTime();
        if (expireTime.before(new Date())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "此队伍已过期");
        }
        userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        // 队伍里的用户列表
        List<UserTeam> userTeamList = userTeamMapper.selectList(userTeamQueryWrapper);
        if (userTeamList.size() == team.getMaxNum().longValue()) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "此队伍人数已满");
        }
        //不能重复加入队伍
        for (UserTeam userTeam : userInsertTeamList) {
            if (userTeam.getTeamId() == teamId) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "不能重复加入队伍");
            }
        }
        // 不能加入私有的队伍
        if (PRIVATE.getKey().equals(team.getStatus())) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "不能加入私有的队伍");
        }
        // 加入加密的队伍，密码需要正确
        if (ENCRYPTION.getKey().equals(team.getStatus())) {
            String teamPassword = team.getPassword();
            if (password != null && password.length() != 0) {
                // 加密
                String safetyPwd = DigestUtils.md5DigestAsHex(password.getBytes());
                if (!teamPassword.equals(safetyPwd)) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍密码错误");
                }
            }
        }
        // 新增队伍关系
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(loginUserId);
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(new Date());
        int insertResult = userTeamMapper.insert(userTeam);
        if (insertResult == 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "加入队伍失败");
        }
        return insertResult;
    }

    /**
     * 退出队伍
     *
     * @param teamId  队伍id
     * @param request 请求
     * @return 是否退出成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int quitTeam(long teamId, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        long loginUserId = loginUser.getId();
        // 队伍是否存在
        Team team = getTeamById(teamId, request);
        if (team == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍不存在");
        }
        // 是否加入此队伍
        UserTeam userTeam = getUserByTeamId(teamId, loginUserId);
        if (userTeam == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "你没有加入此队伍");
        }
        List<UserTeam> userList = getUserListByTeamId(teamId);
        if (userList == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "此队伍中没有任何人");
        }
        // 判断是否只有你一人
        QueryWrapper<UserTeam> userTeamQueryWrapper = null;
        QueryWrapper<Team> teamQueryWrapper = null;
        if (userList.size() == 1) {
            // 删除队伍
            teamQueryWrapper = new QueryWrapper<>();
            teamQueryWrapper.eq("id", teamId);
            int delete = teamMapper.delete(teamQueryWrapper);
            if (delete == 0) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除队伍失败");
            }
        } else {
            UserTeam firstUser = userList.get(1);
            // 是队长
            if (loginUserId == team.getUserId()) {
                // 权限转移
                teamQueryWrapper = new QueryWrapper<>();
                teamQueryWrapper.eq("id", teamId);
                Team newTeam = new Team();
                newTeam.setUserId(firstUser.getUserId());
                int updateResult = teamMapper.update(newTeam, teamQueryWrapper);
                if (updateResult == 0) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "权限转让失败");
                }
            }
        }
        // 删除关系记录
        int deleteResult = deleteUserTeam(teamId, loginUserId);
        if (deleteResult == 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除关联信息失败");
        }
        return deleteResult;
    }

    /**
     * 删除队伍
     *
     * @param teamId  队伍id
     * @param request 请求
     * @return 是否删除成功
     */
    @Override
    public long deleteTeamById(long teamId, HttpServletRequest request) {
        // 判断是否登录
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        // 队伍是否存在
        Team team = getTeamById(teamId, request);
        if (team == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍不存在");
        }
        // 是否是管理员或队长
        boolean admin = userService.isAdmin(loginUser);
        long loginUserId = loginUser.getId();
        if (!(admin || loginUserId == team.getUserId())) {
            throw new BusinessException(ErrorCode.NO_AUTH, "无权限解散");
        }
        // 删除关联信息
        int deleteUserTeamResult = deleteUserTeam(teamId);
        if (deleteUserTeamResult == 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除关联信息失败");
        }
        // 删除队伍
        int deleteResult = teamMapper.deleteById(teamId);
        if (deleteResult == 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除队伍失败");
        }
        return deleteResult;
    }

    /**
     * 删除某个用户关联信息
     *
     * @param teamId 队伍id
     * @param userId 用户id
     * @return
     */
    private int deleteUserTeam(long teamId, long userId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper;
        userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        userTeamQueryWrapper.eq("userId", userId);
        return userTeamMapper.delete(userTeamQueryWrapper);
    }

    /**
     * 删除这支队伍所有的关联信息
     *
     * @param teamId 队伍id
     * @return
     */
    private int deleteUserTeam(long teamId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper;
        userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        return userTeamMapper.delete(userTeamQueryWrapper);
    }

    /**
     * 判断是否加入此队伍
     *
     * @param teamId      队伍id
     * @param loginUserId 用户id
     * @return 加入的队伍信息
     */
    private UserTeam getUserByTeamId(long teamId, long loginUserId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("userId", loginUserId);
        userTeamQueryWrapper.eq("teamId", teamId);
        return userTeamMapper.selectOne(userTeamQueryWrapper);
    }

    /**
     * 根据退伍id查加入此队伍的用户列表
     *
     * @param teamId 队伍id
     * @return 用户列表信息
     */
    private List<UserTeam> getUserListByTeamId(long teamId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        return userTeamMapper.selectList(userTeamQueryWrapper);
    }

    /**
     * 根据id查队伍
     *
     * @param teamId  队伍id
     * @param request
     * @return 队伍信息
     */
    @Override
    public Team getTeamById(long teamId, HttpServletRequest request) {
        userService.getLoginUser(request);
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", teamId);
        return teamMapper.selectOne(queryWrapper);
    }

    /**
     * 查询我创建的队伍
     *
     * @param searchText 关键字
     * @param request    请求
     * @return 队伍列表
     */
    @Override
    public List<TeamVO> getMyCreateTeam(String searchText, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        long loginUserId = loginUser.getId();
        QueryWrapper<Team> teamQueryWrapper = new QueryWrapper<>();
        teamQueryWrapper.eq("userId", loginUserId);
        if (searchText.length() != 0) {
            teamQueryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
        }
        List<Team> teamList = teamMapper.selectList(teamQueryWrapper);
        List<TeamVO> teamVOList = new ArrayList<>();
        for (Team team : teamList) {
            TeamVO teamVO = new TeamVO();
            BeanUtils.copyProperties(team, teamVO);
            teamVOList.add(teamVO);
        }
        return teamVOList;
    }

    /**
     * 查询我加入的队伍
     *
     * @param searchText 关键字
     * @param request    请求
     * @return 队伍列表
     */
    @Override
    public List<TeamVO> getMyJoinTeam(String searchText, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        long loginUserId = loginUser.getId();
        // 查询录用户加入的队伍关联信息
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("userId", loginUserId);
        List<UserTeam> userTeamList = userTeamMapper.selectList(userTeamQueryWrapper);
        // 查询录用户加入的队伍
        List<TeamVO> teamVOList = new ArrayList<>();
        for (UserTeam userTeam : userTeamList) {
            Long teamId = userTeam.getTeamId();
            QueryWrapper<Team> teamQueryWrapper = new QueryWrapper<>();
            teamQueryWrapper.eq("id", teamId);
            Team team = teamMapper.selectOne(teamQueryWrapper);
            TeamVO teamVO = new TeamVO();
            BeanUtils.copyProperties(team, teamVO);
            teamVOList.add(teamVO);
        }
        // 关键字查询
        if (searchText.length() != 0) {
            for (int i = 0; i < teamVOList.size(); i++) {
                TeamVO teamVO = teamVOList.get(i);
                String name = teamVO.getName();
                String description = teamVO.getDescription();
                if (!(name.startsWith(searchText) || description.startsWith(searchText))) {
                    teamVOList.remove(i);
                    i--;
                }
            }
        }
        return teamVOList;
    }
}




